package com.up.api.xianliu;

import org.springframework.stereotype.Component;

import java.time.LocalTime;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author: liuchengjun
 * @title: SlidingWindow
 * @projectName: 海联技术中台V2.0
 * @depart 软件事业部
 * @description:
 * @date: 2023/12/19/019 10:55 (星期二)
 * @since V2.0
 */
@Component
public class SlidingWindow {
    //50
    private final int maxRequestsPerSecond;
    //200ms
    private final int windowSizeInMilliseconds;
    //窗口
    private final AtomicInteger[] window;

    private final ReentrantLock lock;

    public SlidingWindow() {
        this.maxRequestsPerSecond = 50;
        this.windowSizeInMilliseconds = 500;
        this.window = new AtomicInteger[1000/windowSizeInMilliseconds]; // Each slot represents 100ms
        this.lock = new ReentrantLock();

        for (int i = 0; i < window.length; i++) {
            window[i] = new AtomicInteger(0);
        }
        // Start a background thread to slide the window
        Thread sliderThread = new Thread(() -> {
            while (true) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                slideWindow();
            }
        });
        sliderThread.setDaemon(true);
        sliderThread.start();
    }

    public boolean allowRequest() {
        lock.lock();
        try {
            int currentSlot = (int) (System.currentTimeMillis() % 1000 /windowSizeInMilliseconds);
            int totalRequestsInWindow = 0;
            for (AtomicInteger count : window) {
                totalRequestsInWindow += count.get();
            }

            if (totalRequestsInWindow < maxRequestsPerSecond) {
                window[currentSlot].incrementAndGet();
                return true;
            } else {
                return false;
            }
        } finally {
            lock.unlock();
        }
    }

    private void slideWindow() {
        lock.lock();
        try {
            int currentSlot = (int) (System.currentTimeMillis() % 1000 /windowSizeInMilliseconds);
            window[currentSlot].set(0);
        } finally {
            lock.unlock();
        }
    }
}
